package com.vip.jwt.common.utils.xcx.wx;

import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.vip.jwt.common.exception.MyException;
import com.vip.jwt.common.utils.RedisUtil;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Base64Utils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 微信授权工具类
 */
public class WXAuthUtil {

    @Getter
    private static String APP_ID;

    @Getter
    private static String APP_SECRET;

    @Value("${wx-xcx-appid}")
    public void setAppId(String appId) {
        APP_ID = appId;
    }

    @Value("${wx-xcx-appsecret}")
    public void setAppSecret(String appSecret) {
        APP_SECRET = appSecret;
    }

    /**
     * 检查SessionKey是否有效
     * @param signature sha1(rawData+session_key)，rawData是小程序授权获取到的
     * @param openId 用户唯一标识
     * @return
     */
    public static String checkSessionKey(String signature,String openId){
        String url = "https://api.weixin.qq.com/wxa/checksession?"+"access_token="+getAccessToken()+"&signature="+signature+"&openid="+openId+"&sig_method=hmac_sha256";
        return HttpRequest.get(url).header("Content-type","application/json").execute().body();
    }

    /**
     * 获取SessionKey和Openid（如果sessionKey没有过期，那么再次使用code去获取sessionKey时可能会报错）
     * @return
     */
    public static String getSessionKeyAndOpenid(String wxCode){
        String url = "https://api.weixin.qq.com/sns/jscode2session?"+"appid="+APP_ID+"&secret="+APP_SECRET+"&js_code="+wxCode+"&grant_type=authorization_code";
        return HttpRequest.get(url).header("Content-type","application/json").execute().body();
    }

    /**
     * 获取手机号
     * @param sessionKey 使用code获取的sessionKey（sessionKey需要存在数据库，如果没过期，则使用数据库里面的，如果过期了，则重新获取
     *                   所以这里需要前台先检查是否过期，使用wx.checkSession检查是否过期，使用wx.login获取code）
     * @param encryptedData 加密的数据
     * @param iv 解密串
     * @return
     */
    public static String getPhone(String sessionKey,String encryptedData,String iv){
        //解密
        byte[] encrypData = Base64Utils.decodeFromString(encryptedData);
        byte[] ivData = Base64Utils.decodeFromString(iv);
        byte[] sessionKeyData = Base64Utils.decodeFromString(sessionKey);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivData);
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(sessionKeyData, "AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); //设置为解密模式
            String jsonStr = new String(cipher.doFinal(encrypData), StandardCharsets.UTF_8);
            JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
            return jsonObject.get("phoneNumber").toString();
        } catch (NoSuchAlgorithmException
                | BadPaddingException
                | InvalidKeyException
                | InvalidAlgorithmParameterException
                | NoSuchPaddingException
                | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取令牌
     * @return
     */
    private static String accessToken(){
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+APP_ID+"&secret="+APP_SECRET;
        return HttpRequest.get(url).header("Content-type","application/json").execute().body();
    }

    /**
     * 将百度AccessToken存入Redis
     * @return
     */
    public static String getAccessToken(){
        String key = "wx_xcx_access_token";
        // 首先验证Redis有没有accessToken
        Boolean bo = RedisUtil.hasKey(key);
        String accessTokenStr;
        if(bo){
            accessTokenStr = RedisUtil.get(key);
        }else{
            String jsonStr = accessToken();
            JSONObject jsonObject = JSONUtil.parseObj(jsonStr);
            if(null!=jsonObject.get("errcode")){
                throw new MyException(jsonObject.get("errmsg").toString());
            }
            accessTokenStr = jsonObject.get("access_token").toString();
            RedisUtil.set(key,accessTokenStr);
            int expires_in = Integer.parseInt(jsonObject.get("expires_in").toString());
            RedisUtil.expire(key,expires_in, TimeUnit.SECONDS);
        }
        return accessTokenStr;
    }

    /**
     * 发送订阅消息
     * @param accessToken 令牌
     * @param openId 用户的唯一标识
     * @param dataMap 参数，示例如下：
     *        Map<String,Object> dataMap = new HashMap<>(16);
     *        Map<String,String> thingMap = new HashMap(16);
     *        thingMap.put("value","张三");
     *        dataMap.put("thing2",thingMap);
     *        Map<String,String> phraseMap = new HashMap(16);
     *        phraseMap.put("value","报名成功");
     *        dataMap.put("phrase3",phraseMap);
     */
    public static String sendSubscribeMessage(String accessToken,String templateId,String openId,Map<String,Object> dataMap){
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+accessToken;
        Map<String,Object> params = new HashMap<>(16);
        params.put("touser",openId);
        params.put("template_id",templateId);
        params.put("page","index");
        params.put("miniprogram_state","trial");
        params.put("lang","zh_CN");
        params.put("data",dataMap);
        String dataJson = new JSONObject(params).toString();
        return HttpRequest.post(url).body(dataJson).execute().body();
    }

}